package com.cfswt.tasksystem.controller;

//import com.cfswt.tasksystem.SecurityUtil;

import com.cfswt.tasksystem.pojo.dto.RollbackDTO;
import com.cfswt.tasksystem.pojo.entity.ProcessInstanceRequest;
import com.cfswt.tasksystem.response.JsonResult;
import com.cfswt.tasksystem.security.CustomUserDetails;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.activiti.api.process.model.ProcessInstance;
import org.activiti.api.process.model.builders.ProcessPayloadBuilder;
import org.activiti.api.process.runtime.ProcessRuntime;
import org.activiti.api.runtime.shared.query.Page;
import org.activiti.api.runtime.shared.query.Pageable;
import org.activiti.api.task.runtime.TaskRuntime;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.FlowElement;
import org.activiti.bpmn.model.Process;
import org.activiti.bpmn.model.UserTask;
import org.activiti.engine.*;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.impl.context.Context;
import org.activiti.engine.impl.interceptor.Command;
import org.activiti.engine.impl.interceptor.CommandContext;
import org.activiti.engine.impl.persistence.entity.ExecutionEntity;
import org.activiti.engine.impl.persistence.entity.ExecutionEntityManager;
import org.activiti.engine.impl.persistence.entity.TaskEntity;
import org.activiti.engine.impl.util.ProcessDefinitionUtil;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.Execution;
import org.activiti.engine.task.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@RestController
@RequestMapping("/instance")
@Api(tags = "60.流程实例管理模块")
public class ProcessInstanceController {
    @Autowired
    private RepositoryService repositoryService;
    @Autowired
    private ProcessRuntime processRuntime;
    @Autowired
    private TaskRuntime taskRuntime;
    @Autowired
    private RuntimeService runtimeService;
    @Autowired
    private TaskService taskService;
    @Autowired
    private HistoryService historyService;
    @Autowired
    private ManagementService managementService;

    @ApiOperation(value = "进行中流程实例列表")
    @GetMapping("")
    public JsonResult instances(@AuthenticationPrincipal CustomUserDetails userDetails) {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
        dateFormat.setTimeZone(TimeZone.getTimeZone("GMT+8")); // 设置时区为GMT+8
        Page<ProcessInstance> processInstancePage = processRuntime.processInstances(Pageable.of(0, 100));
        List<ProcessInstance> content = processInstancePage.getContent();
        content.sort((y, x) -> x.getStartDate().toString().compareTo(y.getStartDate().toString()));
        List<HashMap<String, Object>> listMap = new ArrayList<HashMap<String, Object>>();
        for (ProcessInstance processInstance : content) {
            HashMap<String, Object> hashMap = new HashMap<>();
            hashMap.put("ProcessInstanceName", processInstance.getBusinessKey());
            hashMap.put("ProcessInstanceID", processInstance.getId());
            hashMap.put("ProcessDefinitionID", processInstance.getProcessDefinitionId());
            hashMap.put("ProcessDefinitionKey", processInstance.getProcessDefinitionKey());
            hashMap.put("ProcessStartDate", dateFormat.format(processInstance.getStartDate()));
            hashMap.put("BusinessKey", processInstance.getBusinessKey());
            hashMap.put("Status", processInstance.getStatus());
            ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                    .processDefinitionId(processInstance.getProcessDefinitionId())
                    .singleResult();
            hashMap.put("ProcessDeploymentID", processDefinition.getDeploymentId());
            hashMap.put("ProcessResourceName", processDefinition.getResourceName());
            listMap.add(hashMap);
        }
        return JsonResult.ok(listMap);
    }

    @ApiOperation(value = "启动流程实例")
    @PostMapping("/start")
    public JsonResult instance(@RequestBody ProcessInstanceRequest processInstanceRequest) {
        ProcessInstance processInstance = processRuntime.start(ProcessPayloadBuilder
                .start()
                .withProcessDefinitionKey(processInstanceRequest.getInstanceKey())
                .withName(processInstanceRequest.getInstanceName())
                .withVariable("name", processInstanceRequest.getInstanceVariable())
                .withBusinessKey("业务数据表Key")
                .build());
        return JsonResult.ok(processInstance.getName() + ";" + processInstance.getId());
    }

    @ApiOperation(value = "挂起流程实例")
    @PostMapping("/suspend/{id}")
    public JsonResult suspend(@PathVariable(value = "id") String id) {
        ProcessInstance suspend = processRuntime.suspend(ProcessPayloadBuilder
                .suspend()
                .withProcessInstanceId(id)
                .build());
        return JsonResult.ok(suspend.getName());
    }

    @ApiOperation(value = "激活流程实例")
    @PostMapping("/resume/{id}")
    public JsonResult resume(@PathVariable(value = "id") String id) {
        ProcessInstance resume = processRuntime.resume(ProcessPayloadBuilder
                .resume()
                .withProcessInstanceId(id)
                .build());
        return JsonResult.ok(resume.getName());
    }

    @ApiOperation(value = "删除流程实例")
    @DeleteMapping("/delete/{id}")
    public JsonResult instance(@PathVariable String id) {
        runtimeService.deleteProcessInstance(id, "用户请求删除");
        return JsonResult.ok();
    }

    @ApiOperation(value = "获取当前步骤可退回的流程节点")
    @GetMapping("/roolbackNodes/{taskId}")
    public JsonResult getRoolbackNodes(@PathVariable String taskId) {
        String processInstanceId = taskRuntime.task(taskId).getProcessInstanceId();
        List<HistoricActivityInstance> listNodes = historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId)
                .finished().orderByHistoricActivityInstanceEndTime().asc().list();
        List<Map<String, String>> nodes = new ArrayList<>();
        for (HistoricActivityInstance listNode : listNodes) {
            Map<String, String> node = new HashMap<>();
            node.put("activityId", listNode.getActivityId());
            node.put("activityName", listNode.getActivityName());
            node.put("assignee", listNode.getAssignee());
            nodes.add(node);
        }
        return JsonResult.ok(nodes);
    }

    @ApiOperation(value = "撤回流程实例(未审批)")
    @PostMapping("/rollback/{processInstanceId}")
    public JsonResult rollback(@PathVariable String processInstanceId) {
        List<HistoricTaskInstance> completedTasks = historyService.createHistoricTaskInstanceQuery()
                .processInstanceId(processInstanceId)
                .finished()
                .orderByHistoricTaskInstanceEndTime()
                .asc()
                .list();
        if (completedTasks.size() == 1) {
            runtimeService.deleteProcessInstance(processInstanceId, "撤回流程");
            return JsonResult.ok();
        } else {
            return JsonResult.error(2002, "流程已被审批，撤回失败");
        }
    }


    @ApiOperation(value = "根据选中的节点进行回滚")
    @PostMapping("/rollback/")
    @Transactional
    public JsonResult rollbackNode(@RequestBody RollbackDTO rollbackDTO, @AuthenticationPrincipal CustomUserDetails userDetails) {
        String taskId = rollbackDTO.getTaskId();
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        System.out.println(task.getAssignee());
        String toActivityId = rollbackDTO.getActivityId();
        System.out.println(toActivityId);
        String processInstanceId = taskRuntime.task(rollbackDTO.getTaskId()).getProcessInstanceId();
        if (task.getAssignee().equals(userDetails.getUsername())) {
            String fromActivityId = task.getTaskDefinitionKey();
            System.out.println(fromActivityId);
            DynamicJumpCmd dynamicJumpCmd = new DynamicJumpCmd(processInstanceId, fromActivityId, toActivityId);
            managementService.executeCommand(dynamicJumpCmd);
            return JsonResult.ok("Command executed successfully");
        } else {
            return null;
        }
    }

    @Data
    @AllArgsConstructor
    public class DynamicJumpCmd implements Command<Void> {
        protected String processInstanceId;
        protected String fromActivityId;
        protected String toActivityId;

        public Void execute(CommandContext commandContext) {
            if (this.processInstanceId == null) {
                throw new ActivitiIllegalArgumentException("process instance id is required");
            }
            ExecutionEntityManager executionEntityManager = commandContext.getExecutionEntityManager();
            System.out.println(executionEntityManager);
            ExecutionEntity execution = (ExecutionEntity) executionEntityManager.findById(this.processInstanceId);
            if (execution == null) {
                throw new ActivitiException("Execution could not be found with id" + this.processInstanceId);
            }
            if (!execution.isProcessInstanceType()) {
                throw new ActivitiException("Execution is not a process instance type execution for id" + this.processInstanceId);
            }
            ExecutionEntity activeExecutionEntity = null;
            List<ExecutionEntity> childExecutions = executionEntityManager.findChildExecutionsByProcessInstanceId(execution.getId());
            for (ExecutionEntity childExecution : childExecutions) {
                if (childExecution.getCurrentActivityId().equals(this.fromActivityId)) {
                    activeExecutionEntity = childExecution;
                }
            }
            if (activeExecutionEntity == null) {
                throw new ActivitiException("Active execution could not be found with activity id" + this.fromActivityId);
            }
            BpmnModel bpmnModel = ProcessDefinitionUtil.getBpmnModel(execution.getProcessDefinitionId());
            FlowElement fromActivityElement = bpmnModel.getFlowElement(this.fromActivityId);
            FlowElement toActivityElement = bpmnModel.getFlowElement(this.toActivityId);
            if (fromActivityElement == null) {
                throw new ActivitiException("Activity could not be found in process definition for id" + this.fromActivityId);
            }
            if (toActivityElement == null) {
                throw new ActivitiException("Activity could not be found in process definition for id" + this.toActivityId);
            }
            boolean deleteParentExecution = false;
            ExecutionEntity parentExecution = activeExecutionEntity.getParent();
            if ((fromActivityElement.getSubProcess() != null) && ((toActivityElement.getSubProcess() == null) || (!toActivityElement.getSubProcess().getId().equals(parentExecution.getActivityId())))) {
                deleteParentExecution = true;
            }
            executionEntityManager.deleteExecutionAndRelatedData(activeExecutionEntity, "change activity to" + this.toActivityId, false);
            if (deleteParentExecution) {
                executionEntityManager.deleteExecutionAndRelatedData(parentExecution, "change activity to " + this.toActivityId, false);
            }
            ExecutionEntity newChildExecution = executionEntityManager.createChildExecution(execution);
            newChildExecution.setCurrentFlowElement(toActivityElement);
            // 获取目标节点的 formKey 和其他属性
            String formKey = null;
            String taskName = null;
            if (toActivityElement instanceof UserTask) {
                UserTask userTask = (UserTask) toActivityElement;
                formKey = userTask.getFormKey();
                taskName = userTask.getName();
            }
            System.out.println(formKey + taskName);
            TaskService taskService = Context.getProcessEngineConfiguration().getTaskService();
            TaskEntity newTask = (TaskEntity) taskService.newTask();
            newTask.setExecutionId(newChildExecution.getId());
            newTask.setProcessInstanceId(this.processInstanceId);
            newTask.setTaskDefinitionKey(this.toActivityId);
            newTask.setName(taskName != null ? taskName : toActivityElement.getName());
            newTask.setFormKey(formKey); // 显式设置 formKey
            taskService.saveTask(newTask); // 保存任务
            Context.getAgenda().planContinueProcessOperation(newChildExecution);
            return null;
        }
    }

    @ApiOperation(value = "我发起的流程实例")
    @GetMapping("/personal")
    public JsonResult personalInstance(@AuthenticationPrincipal CustomUserDetails userDetails) {
        List<Map<String, Object>> result = runtimeService.createProcessInstanceQuery()
                .startedBy(userDetails.getNickName())
                .list()
                .stream()
                .map(instance -> {
                    Map<String, Object> map = new HashMap<>();
                    map.put("processInstanceId", instance.getProcessInstanceId());
                    map.put("id", instance.getId());
                    map.put("startTime", instance.getStartTime());
                    map.put("businessKey", instance.getBusinessKey());
                    // 确保任务查询也在同一个命令上下文中执行
                    List<org.activiti.engine.task.Task> tasks = taskService.createTaskQuery()
                            .processInstanceId(instance.getId())
                            .active() // 确保只查询活动的任务
                            .list();
                    System.out.println("激活状态任务：" + tasks);
                    String currentTasks = tasks.stream()
                            .map(task -> task.getName())  // 使用 lambda 表达式代替方法引用
                            .collect(Collectors.joining(", "));
                    map.put("currentTask", currentTasks);
                    String assignees = tasks.stream()
                            .map(task -> task.getAssignee())
                            .distinct()
                            .filter(Objects::nonNull)
                            .collect(Collectors.joining(", "));
                    map.put("assignee", assignees);
                    return map;
                })
                .collect(Collectors.toList()); // 收集转换后的结果
        System.out.println(result);
        return JsonResult.ok(result);
    }

}
